package main

/**
系统监控展示/操作台
*/

import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"monitorc/model"
	"net/http"
	"net/rpc"
	"net/rpc/jsonrpc"
	"os"
	"os/exec"
	"strings"

	"github.com/gin-gonic/gin"
)

var rpcConn = make(map[string]*rpc.Client)
var db model.AppInfoDB
var port = "9321"

func main() {

	os.Mkdir("tmp", 0777)
	os.Mkdir("data", 0777)

	if len(os.Args) > 1 {
		port = os.Args[1]
	}

	//初始化web服务器
	r := gin.Default()
	r.Static("/static", "web/static")
	r.LoadHTMLGlob("web/templates/**")
	router := r.Group("/", gin.BasicAuth(gin.Accounts{
		"admin":      "admin123",
		"test":       "test123",
		"sirui":      "sirui",
		"payexpress": "payexpress",
	}))
	router.GET("/", Home)
	router.GET("/server", Server)
	router.POST("/server", Server)
	router.POST("/del", Del)
	router.GET("/upload", Upload)
	router.POST("/upload", Upload)
	router.POST("/start", Start)
	router.POST("/stop", Stop)
	router.GET("/logs", Logs)
	router.POST("/logs", Logs)
	router.POST("/clear", Clear)
	r.Run(":" + port)
}

func Home(c *gin.Context) {
	c.HTML(http.StatusOK, "home.html", db.ReadAll())
}

func Upload(c *gin.Context) {
	if c.Request.Method == "GET" {
		id := c.Query("id")
		c.HTML(http.StatusOK, "upload.html", id)
		return
	}
	file, header, err := c.Request.FormFile("file")
	if err != nil {
		c.JSON(http.StatusOK, gin.H{"result": true, "msg": "文件上传失败"})
		return
	}

	out, err := os.Create("tmp/" + header.Filename)
	if err != nil {
		log.Fatal("保存文件失败")
	}
	defer out.Close()
	io.Copy(out, file)
	var msg string
	if header.Filename == "monitorc.zip" {
		shell("mv tmp/" + header.Filename + " ./data")
		c.JSON(http.StatusOK, gin.H{"result": true, "msg": "升级成功"})
		shell("rm -rf tmp/" + header.Filename)
		return
	} else if header.Filename == "monitors.zip" {
		var count = 0
		for n, v := range db.ReadAll() {
			m, _ := uploadSend(v, header.Filename)
			msg = m + msg
			count = n
		}

		n := strings.Count(msg, "升级成功")
		msg = fmt.Sprintf("总服务数：%d,升级成功：%d", count, n)
	} else {
		id := c.Query("id")
		s := db.Get(id)
		msg, err = uploadSend(s, header.Filename)
		if err != nil {
			shell("rm -rf tmp/" + header.Filename)
			c.JSON(http.StatusOK, gin.H{"result": false, "msg": err.Error()})
		}
	}
	shell("rm -rf tmp/" + header.Filename)
	c.JSON(http.StatusOK, gin.H{"result": true, "msg": msg})
}

func uploadSend(s model.AppInfo, filename string) (string, error) {
	client, err := connect(s)
	if err != nil {
		return "", err
	}

	var msg string
	bs, _ := ioutil.ReadFile("tmp/" + filename)
	param := make(map[string][]byte)
	d, _ := json.Marshal(s)
	param["s"] = d
	param["data"] = bs
	param["filename"] = []byte(filename)
	client.Call("Server.Upload", param, &msg)
	if msg == "" {
		delete(rpcConn, s.Name)
		msg = "失败，请重试"
	}
	return msg, nil
}

func shell(s string) (string, error) {
	cmd := exec.Command("/bin/bash", "-c", s)

	var out bytes.Buffer
	cmd.Stdout = &out
	err := cmd.Run()

	return out.String(), err
}

func connect(s model.AppInfo) (*rpc.Client, error) {
	fmt.Println(s)
	c := rpcConn[s.Name]
	if c != nil {
		return c, nil
	}
	fmt.Println("创建连接")
	client, err := jsonrpc.Dial("tcp", s.ServerAddr)
	if err != nil {
		return nil, errors.New("失败，请重试")
	}
	rpcConn[s.Name] = client
	return client, nil
}

func Server(c *gin.Context) {
	if c.Request.Method == "GET" {
		id := c.Query("id")
		c.HTML(http.StatusOK, "server.html", db.Get(id))
		return
	}
	s := model.AppInfo{}
	c.ShouldBindJSON(&s)
	db.Write(s)
	c.JSON(http.StatusOK, gin.H{"result": true, "msg": "成功"})
}

func Del(c *gin.Context) {
	id := make(map[string]string)
	c.ShouldBindJSON(&id)
	appid := id["id"]
	db.Del(appid)
	ct := rpcConn[appid]
	if ct != nil {
		ct.Close()
		delete(rpcConn, appid)
	}
	c.JSON(http.StatusOK, gin.H{"result": true, "msg": "删除成功"})
}

func Start(c *gin.Context) {
	id := c.Query("id")
	s := db.Get(id)
	client, err := connect(s)
	if err != nil {
		c.JSON(http.StatusOK, gin.H{"result": false, "msg": err.Error()})
		return
	}
	var msg string
	client.Call("Server.Start", s, &msg)
	if msg == "" {
		delete(rpcConn, s.Name)
		msg = "失败，请重试"
	}
	c.JSON(http.StatusOK, gin.H{"result": true, "msg": msg})
}

func Stop(c *gin.Context) {
	id := c.Query("id")
	s := db.Get(id)
	fmt.Println(id, s)
	client, err := connect(s)
	if err != nil {
		c.JSON(http.StatusOK, gin.H{"result": false, "msg": err.Error()})
		return
	}
	var msg string
	client.Call("Server.Stop", s, &msg)
	if msg == "" {
		delete(rpcConn, s.Name)
		msg = "失败，请重试"
	}
	c.JSON(http.StatusOK, gin.H{"result": true, "msg": msg})
}

func Logs(c *gin.Context) {
	if c.Request.Method == "GET" {
		id := c.Query("id")
		s := db.Get(id)
		c.HTML(http.StatusOK, "logs.html", s)
		return
	}
	id := c.PostForm("id")
	date := c.PostForm("date")
	size := c.PostForm("size")
	s := db.Get(id)
	client, err := connect(s)
	if err != nil {
		c.JSON(http.StatusOK, gin.H{"size": 0, "data": err.Error()})
		return
	}
	var context = make(map[string]interface{})
	params := make(map[string][]byte)
	jb, _ := json.Marshal(s)
	params["s"] = jb
	params["date"] = []byte(date)
	params["size"] = []byte(size)

	client.Call("Server.Logs", params, &context)

	if len(context) == 0 {
		delete(rpcConn, s.Name)
		context["size"] = 0
		context["data"] = "未获取到任何数据！！！"
	}
	c.JSON(http.StatusOK, context)
}

func Clear(c *gin.Context) {
	id := c.PostForm("id")
	date := c.PostForm("date")
	s := db.Get(id)
	client, err := connect(s)
	if err != nil {
		c.JSON(http.StatusOK, gin.H{"size": 0, "data": err.Error()})
		return
	}

	params := make(map[string][]byte)
	jb, _ := json.Marshal(s)
	params["s"] = jb
	params["date"] = []byte(date)
	var context string
	client.Call("Server.Clear", params, &context)

	if len(context) == 0 {
		delete(rpcConn, s.Name)
		context = "失败，请重试"
	}
	c.JSON(http.StatusOK, gin.H{"data": context})
}
